package roborally.itemsonboard;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import roborally.board.Board;
import roborally.factory.PhysicalAmountFactory;
import roborally.shoot.Shoot;
import roborally.supporting.PhysicalAmount;
import roborally.supporting.DefaultConstants;
import roborally.supporting.Direction;
import roborally.supporting.Unit;
import roborally.supporting.Orientation;
import roborally.supporting.Position;
import roborally.usableitems.Usable;
import sortedcollection.SortedCollection;

import dijkstra.*;

import exception.IllegalPositionException;
import exception.IllegalPositionOnBoardException;
import exception.NegativeAmountException;

import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Raw;

/**
 * A class representing a robot. A robot can move and turn, consuming energy.
 * The robot can pick up, use and drop items.
 * A robot can shoot and this will remove an item form the board.
 * A robot can calculate the minimum energy required to reach a particular position on the board.
 * Finally, a 2 robots can move as efficient as possible to each other, minimizing the 
 * Manhattan distance between them.
 * 
 * @invar The robot must have a valid orientation at all times.
 * 		| isValidOrientation(this.getOrientation())
 * @invar The robot must carry proper usable items.
 * 		| hasProperUsableItems()
 * 
 * @author Molderez Tom, 2de bach Ingenieurswetenschappen Computerwetenschappen-Elektrotechniek and Reniers Jorn, 2de bach Ingenieurswetenschappen Werktuigkunde-Computerwetenschappen
 * @version 5.0
 *
 */
public class Robot extends EnergyItem implements Shoot {
//constructors -----------------------------------------------------------------------------------------------
	
	/**
	 * Constructs a new Robot with the given options.
	 * 
	 * @param position The position of the robot.
	 * @param orientation The orientation of the robot.
	 * @param energyLevel The energyLevel of the robot.
	 * @param energyLimit The energyLimit of the robot.
	 * @param board The board at which the new robot should be, null is allowed.
	 * @pre The energyLimit must be possible.
	 * 		| isPossibleEnergyLimit(energyLimit)
	 * @pre The energyLevel must be positive and smaller than or equal to energyLimit
	 * 		| canHaveAsEnergyLevel(energyLevel)
	 * @effect The orientation is set to the given orientation.
	 * 		| setOrientation(orientation)
	 * @effect The energyLimit, the energyLevel, board and position of the robot is set to the given value
	 * 		| super(energyLimit, energyLevel, board position)
	 * @throws IllegalArgumentException
	 * 		Position is null or the board can't have this new PositionItem.
	 * 		| position== null || ( board != null && !board.canHaveAsItem(new this) )
	 */
	@Raw
	public Robot(Position position, Orientation orientation, PhysicalAmount energyLevel, PhysicalAmount energyLimit, Board board ) throws IllegalArgumentException {
		super(energyLimit, energyLevel,board,position);
		assert(energyLimit.compareTo(DefaultConstants.ROBOT_ENERGY_LIMIT)==-1 || (energyLimit.compareTo(DefaultConstants.ROBOT_ENERGY_LIMIT)==0) );
		setOrientation(orientation);
	}
	
	/**
	 * Constructs a new Robot with the given options and a default energy limit.
	 * 
	 * @param position The position of the robot.
	 * @param orientation The orientation of the robot.
	 * @param energyLevel The energyLevel of the robot.
	 * @pre The energyLevel must be positive and smaller than or equal to energyLimit
	 * 		| canHaveAsEnergyLevel(energyLevel)
	 * @effect Creates a new robot with the default energy limit and no board.
	 * 		| this(position,orientation,energyLevel,DefaultEnergyConstants.ROBOT_ENERGY_LIMIT,null)
	 * @throws IllegalArgumentException
	 * 		Position is null
	 * 		| position== null
	 */
	@Raw
	public Robot(Position position, Orientation orientation, PhysicalAmount energyLevel) throws IllegalArgumentException {
		this(position, orientation,energyLevel, DefaultConstants.ROBOT_ENERGY_LIMIT,null);
	}
	
	/**
	 * Creates a new Robot with the given options and a default maximum energyLevel.
	 * 
	 * @param position The position of the robot.
	 * @param orientation The orientation of the robot
	 * @effect Creates a new Robot with maximum amount of energy.
	 * 		| this(position,orientation, getEnergyLimit())
	 * @throws IllegalArgumentException
	 * 		Position is null.
	 * 		| position== null
	 */
	@Raw
	public Robot(Position position, Orientation orientation) throws IllegalArgumentException {
		this(position, orientation, DefaultConstants.ROBOT_ENERGY_LIMIT);
	}
	
	/**
	 * Creates a new Robot at the given position and a default options.
	 * 
	 * @param position The position of the robot.
	 * @effect Creates a now Robot at the given position.
	 * 		| this(position,Orientation.UP)
	 * @throws IllegalArgumentException
	 * 		Position is null.
	 * 		| position== null
	 */
	@Raw
	public Robot(Position position) {
		this(position, Orientation.UP);
	}
	
	/**
	 * Creates a new Robot with the given option and a default position and orientation.
	 * 
	 * @param energyLevel The energyLevel of the robot.
	 * @pre The energyLevel must be positive and smaller than or equal to energyLimit.
	 * 		| canHaveAsEnergyLevel(energyLevel)
	 * @effect Creates a new robot, localized at the origin and with orientation UP.
	 * 		| this(Position.Origin,Orientation.UP,energyLevel)
	 */
	@Raw
	public Robot(PhysicalAmount energyLevel) {
		this(Position.ORIGIN, Orientation.UP, energyLevel);
	}
	
	/**
	 * Creates a default Robot.
	 * 
	 * @effect Creates a new robot, localized at the origin, UP orientated and with maximum energy given the default energy limit.
	 * 		| this(DefaultEnergyConstants.ROBOT_ENERGY_LIMIT)
	 */
	@Raw
	public Robot() {
		this(DefaultConstants.ROBOT_ENERGY_LIMIT);
	}
	
	
// Destructor ------------------------------------------------------------------------------------------
	
	/**
	 * Terminates this robot and all items it is carrying. These items are also removed from this robot.
	 * 
	 * @effect Terminates all items the robot is carrying.
	 * 		| for each usable in {this.getAllUsables()}
	 * 		|	usables.terminate()
	 * @effect Terminates this item as an EnergyItem does.
	 * 		| super.terminate()
	 * @post Removes all items this robot is carrying.
	 * 		| (new this).getAllUsables().isEmpty() == true
	 */
	@Raw @Override
	public void terminate() {
		for (Usable lusUsable : usables)
			lusUsable.terminate();
		usables.clear();		
		super.terminate();
	}
	
//orientation: total -----------------------------------------------------------------------------------
	
	/**
	 * Returns the orientation of the robot.
	 */
	@Basic @Raw
	public Orientation getOrientation() {
		return this.orientation;
	}

	/**
	 * Sets the orientation to the given value. 
	 *
	 * @param orientation The orientation to be set.
	 * @post The new orientation will be the given one is this is a valid orientation.
	 * 		| if(isValidOrientation())
	 * 		|	(new this).getOrientation() == orientation
	 */
	@Raw
	public void setOrientation(Orientation orientation) {
		if(isValidOrientation(orientation))
			this.orientation = orientation;
	}
	
	/**
	 * Checks whether this orientation is valid.
	 * 
	 * @param orientation The orientation to be checked.
	 * @return 
	 * 		| result == orientation != null
	 */
	public static boolean isValidOrientation(Orientation orientation) {
		assert Orientation.isProperOrientations(); // orientation is not Raw, so must satisfy its invariants
		return orientation != null;
	}
	
	/**
	 * The orientation of the robot.
	 */
	private Orientation orientation;
	
//position: defensively ----------------------------------------------------------------------------------------
	
	/**
	 * Checks whether this robot can share a position with the given positionItem.
	 * 
	 * @param positionItem The item which is at the same position as this robot.
	 * @return False if positionItem is null.
	 * 		| if positionItem == null
	 * 		|	then result == false
	 * @return False if positionItem is a Wall.
	 * 		| if Wall.class.isInstance(positionItem)
	 *		|	then result == false
	 * @return True if positionItem is a battery.
	 * 		| if Battery.class.isInstance(positionItem)
	 *		|	then result == true
	 * @return True if positionItem is a robot and is this.
	 * 		| if Robot.class.isInstance(positionItem)
	 *		|	then result == (positionItem == this)
	 * @return When another type of positionItem is created, in the future, he is responsible for handling this.
	 * 		| result == positionItem.canHaveItemOnSamePosition(this)
	 */
	@Override
	public boolean canHaveItemOnSamePosition(BoardItem positionItem) {
		if(positionItem == null)
			return false;
		else if(Wall.class.isInstance(positionItem))
			return false;
		else if(Battery.class.isInstance(positionItem))
			return true;
		else if(Robot.class.isInstance(positionItem))
			return positionItem == this;
		else
			return positionItem.canHaveItemOnSamePosition(this);
	}
//energy: nominally -------------------------------------------------------------------------------------------
	
	/**
	 * Controls if energyLimit is possible
	 * 
	 * @param energyLimit The energyLimit to be controlled.
	 * @return False if the energyLimit is null.
	 * 		| if energyLimit == null
	 * 		|	then result == false
	 * @return False if the units are different from Ws.
	 * 		| if energyLimit.getUnit() != Unit.WATTSECOND
	 * 		|	then result == false
	 * @return False if the energyLimit has zero as value.
	 * 		| if energyLimit.equals(EnergyAmount.ZERO)
	 * 		|	then result == false
	 * @return False if the energyLimit is negative.
	 * 		| if energyLimit.getAmount() < 0
	 * 		|	then result == false
	 * @return False if the energyLimit is greater then the default one.
	 * 		| if energyLimit.compareTo(DefaultConstants.ROBOT_ENERGY_LIMIT) != 1
	 * 		|	then result == false
	 */
	@Override
	public boolean isPossibleEnergyLimit(PhysicalAmount energyLimit) {
		return super.isPossibleEnergyLimit(energyLimit) && 
				energyLimit.compareTo(DefaultConstants.ROBOT_ENERGY_LIMIT) != 1;
	}
	
	/**
	 * Decreases the energy level by the given amount
	 * 
	 * @param energy the energy amount to subtract.
	 * @pre The item may not be terminated.
	 * 		| !isTerminated()
	 * @pre	the amount must be positive.
	 * 		| energy >= 0
	 * @pre	The value of energyLevel decreased by energy must be valid.
	 * 		| PhysicalAmount.isValidAmount(getEnergyLevel().getAmount()-energy.getAmount()) 
	 * 		| 	&& canHaveAsEnergyLevel(getEnergyLevel().subtractPhysicalAmounts(energy))
	 * @effect has the same result as setting the energy level to the current energy level minus the amount indicated by energy.
	 * 		| setEnergyLevel(getEnergyLevel().subtract(energy))
	 */
	@Raw
	public void consumeEnergy(PhysicalAmount energy) {
		assert(!isTerminated());
		assert getEnergyLevel().getAmount() - energy.getAmount() >= 0 ;
		energy = getEnergyLevel().subtract(energy);
		setEnergyLevel(energy);
	}
	
	/**
	 * Increase the energy level of this item by the given amount.
	 * 
	 * @param energy The amount to be added.
	 * @pre The item may not be terminated.
	 * 		| !isTerminated()
	 * @pre The amount must be positive.
	 * 		| energy >= 0
	 * @pre	The value of energyLevel increased by energy must be valid.
	 * 		| canHaveAsEnergyLevel(getEnergyLevel().addPhysicalAmounts(energy))
	 * @effect has the same result as setting the energy level to the current energy level plus the 
	 * 			amount indicated by energy if allowed.
	 * 		| setEnergyLevel(getEnergyLevel().add(energy))
	 */
	public void recharge(PhysicalAmount energy) {
		assert(!isTerminated());
		energy = getEnergyLevel().add(energy);
		setEnergyLevel(energy); // the precondition is checked here
	}
	
	/**
	 * Calculates the minimum energy required to reach a given position.
	 * 
	 * @param position The position to be reached.
	 * @pre The the position must be valid.
	 * 		| canHaveAsPosition(position)
	 * 
	 * @return The minimum amount of energy to reach the given position. If the robot can't be on that position or if the board of 
	 * 			this robot is null, or if the robot hasn't enough energy to reach that position or if the position is not reacheble
	 * 			then the result is POSITIVE_INFINITY.
	 * 		| if this.getBoard() == null || !this.canHaveAsPosition(position)
	 * 		|	then result == PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND)
	 * 		| let this.getPosition() be x(0) and position be x(n)
	 * 		| for each position x(i) in {x(0),x(1),...,x(n) | x(i).getManhattanDistance(x(i+1)) == 1 && x(0).getManhattanDistance(x(i)) == i}: 
	 * 		|		this.setPosition(x)
	 * 		|		if(this.getBoard().canHaveAsPosition(x(i+1))
	 * 		|			let Robot thisNext = new Robot()
	 * 		|				this.getBoard().addAsItemAt(thisNext)
	 * 		|				this.setPosition(x(i+1)
	 * 		|			for each position p in {x(i).getLegalNeighbors}
	 * 		|				let Robot otherNext= this.copy().setPosition(p)
	 * 		|				this.getEnergyRequiredToReach(x+1) + thisNext.getEnergyRequiredToReach(x+2)
	 * 		|					<= this.getEnergyRequiredToReach(p) + otherNext.getEnergyRequiredToReach(x+2)
	 * 		|			if x(i).equals(position)
	 * 		|				then break
	 * 		| let Robot thisNext1 = this.copy().setPosition(x1), Robot robot thisNext2 = thisNext1.copy().setPosition(x2),...
	 * 		| let total be this.getEnergyRequiredToReach(x1) + thisNext1.getEnergyRequiredToReach(x2) + thisNext2.getEnergyRequiredToReach(x3) + ...
	 * 		|	if total>this.getEnergyLevel()
	 * 		|		then result == PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND)
	 * 		|	else
	 * 		|		result == total
	 * 
	 * @return The minimum amount of energy to reach the given position. If the robot can't be on that position or if the board of 
	 * 			this robot is null, or if the robot hasn't enough energy to reach that position or if the position is not reacheble
	 * 			then the result is POSITIVE_INFINITY.
	 * 		| if this.getBoard() == null || !this.canHaveAsPosition(position)
	 * 		|	then result == PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND)
	 * 		| else
	 * 		|	let boardPositions = {x | Position.class.isInstance(x) && this.getBoard().canHaveAsItem(new Robot(x)}
	 * 		| 	let sequences = {{x,y,...},{x,y,...}, ... | Position.isInstance(x) && x is in boardPosition, Position.isInstance(y) && y is in boardPosition, ...}
	 * 		|	let energies = {empty}
	 * 		|	for each sequence in sequences
	 * 		|		if sequence.contains(this.getPosition) && sequence.contains(position) &&
	 * 		|					 for each i in {x| x >= 1 && x < sequence.size()} sequence(i-1).nextTo(sequence(i))
	 * 		|			then let turns = 0
	 * 		|			for each i in {x|x>=2 && x < sequence.size()}
	 * 		|				if !sequence(i-2).onOneLine(sequence(i))
	 * 		|					then turns = turns + 1
	 * 		|			energies.add(turns * DefaultConstants.ROBOT_ENERGY_TURN + 
	 * 		|						(DefaultConstants.ROBOT_ENERGY_MOVEMENT + this.getWeightCarried() * DefaultConstants.ROBOT_ENERGY_MOVEMENT_PER_WEIGHT) * sequences.size())
	 * 		|	for each energy in energies
	 * 		|		result <= energy
	 * 		|	if for none energy in energies energy <= this.getEnergyLevel
	 * 		|		then result == PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND)
	 * @note Each element in a collection in comment is different. So let a = {x} and b = {x}, then a and b contains a different item.
	 * @note Normally one of the 2 specifications must describe the result properly. (If one of those should be not 
	 * 		correct, it will be an upper limit for the return value).
	 */
	public PhysicalAmount getEnergyRequiredToReach(Position position) {
		if(this.getBoard() == null || !this.canHaveAsPosition(position))
			return PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY, Unit.WATTSECOND);
		else {
			ReachParticularPosition dijkstra = new ReachParticularPosition(this, position);
			dijkstra.run();
			if(dijkstra.getVertexToReach().getEnergyToReach().compareTo(this.getEnergyLevel())==1)
                return PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND);
			else
				return dijkstra.getVertexToReach().getEnergyToReach();
		}
	}
	
	
	
// Turning: total ----------------------------------------------------------------------------------------------------
	
	/**
	 * Turns the robot to right or left according to direction.
	 * 
	 * @param direction The orientation to be turned to.
	 * @pre	The value of energyLevel decreased by the energy needed to turn must be valid.
	 * 		| PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount()- DefaultConstants.ROBOT_ENERGY_TURN.getAmount())
	 * 		|	&& canHaveAsEnergyLevel(getEnergyLevel().subtract(DefaultConstants.ROBOT_ENERGY_TURN))
	 * @effect Turns the robot according to direction if the robot has enough energy to do so.
	 * 		| if(!isTerminated() && getEnergyLevel() >= Robot.ENERGY_ROTATION)
	 * 		|	then setOrientation(this.getOrientation.turn(direction))
	 * @effect Consumes an amount of energy if the robot has enough energy to turn, and if direction is not null.
	 * 		| if !isTerminated()
	 * 		| 	then if direction != null
	 * 		|		then consumeEnergy(DefaultConstants.ROBOT_ENERGY_TURN)
	 */
	public void turn(Direction direction) {
		if(!isTerminated()) {
			if(direction != null)
				consumeEnergy(DefaultConstants.ROBOT_ENERGY_TURN);
			this.setOrientation(this.getOrientation().turn(direction));
			
		}
	}
	
	/**
	 * Turns the robot some steps, while consuming the needed energy, to the right or left depending on the sign of steps,
	 * if he has the required energy level.
	 * 
	 * @param steps The number of times the robot must turn 90 degrees, a negative number turns counterclockwise, a positive turns clockwise.
	 * @pre	The value of energyLevel decreased by steps times the energy needed to turn must be valid.
	 * 		| PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - DefaultConstants.ROBOT_ENERGY_TURN.multiply(Maths.abs(steps)).getAmount())
	 * 		| canHaveAsEnergyLevel(  getEnergyLevel().subtract( DefaultConstants.ROBOT_ENERGY_TURN.multiply(Maths.abs(steps)) )  )
	 * @effect Turns the robot according to the sign of steps if the robot has enough energy to do so and is he isn't terminated.
	 * 		| if !isTerminated()
	 * 		|	then this.setOrientation(this.getOrientation().turn(steps))
	 * @effect Consumes energy if the robot is not terminated.
	 * 		| if !isTerminated()
	 * 		|	then consumeEnergy(DefaultConstants.ROBOT_ENERGY_TURN.multiply(Math.abs(steps)))
	 */
	public void turn(int steps) {
		if(!isTerminated()) {
			consumeEnergy(DefaultConstants.ROBOT_ENERGY_TURN.multiply(Math.abs(steps))); // the precondition is checked here
			this.setOrientation(this.getOrientation().turn(steps));
		}
	}
		
//shooting ----------------------------------------------------------------------------------------------------------------
	
	/**
	 * If this can shoot then the first item on the board of this robot, in the direction of the orientation of this robot 
	 * will be hit. When the board contains multiple items at the same particular position, a random item will be chosen.
	 * 
	 * @effect If this can shoot,
	 * 			then the first item on the board of this robot, in the direction of the orientation of this robot will be hit. 
	 * 			When the board contains multiple items at the same particular position, a random item will be chosen.
	 * 		| if canShoot()
	 * 		|	then consumeEnergy(DefaultConstants.ROBOT_ENERGY_SHOOT)
	 * 		|		let flag = true
	 * 		|		for the first position in {this.getPosition().move(this.getOrientation), this.getPosition().move(this.getOrientation).move(this.getOrientation(), ...} 
	 * 		|			if this.getBoard().canHaveAsPosition(position) && !this.getBoard().getItemsAt(position).isEmpty() && flag
	 * 		|				this.getBoard().getRandomAtPosition(lusPosition).beenShot()
	 * 		|				flag = false 									
	 */
	@Override
	public void shoot() {
		if(canShoot()) {
			consumeEnergy(DefaultConstants.ROBOT_ENERGY_SHOOT); // preconditions are checked so they are dropped.
			boolean flag = true;
			try {
				Position lusPosition = this.getPosition();
				while(flag) {
					lusPosition = lusPosition.move(this.getOrientation());
					if(!this.getBoard().canHaveAsPosition(lusPosition))
						flag = false; // we have left the board at the right or down side without having shot something.
					else if(!this.getBoard().getItemsAt(lusPosition).isEmpty()) {
						this.getBoard().getRandomAtPosition(lusPosition).beenShot();
						flag = false;
					} 
				}
			} catch(IllegalPositionException exc) { // we have left the board at the left or upper side without having shot something.
			}
		}
	}
	
	/**
	 * Controls if this can shoot.
	 * 
	 * @return False if this is terminated.
	 * 		| if this.isTerminated()
	 * 		|	then result == false
	 * @return False if this has no board.
	 * 		| if this.getBoard() == null
	 * 		|	then result == false
	 * @return False if this has not enough energy to shoot.
	 * 		| if !PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - DefaultConstants.ROBOT_ENERGY_SHOOT.getAmount()
	 * 		|		|| !this.canHaveAsEnergyLevel(this.getEnergyLevel().subtractPhysicalAmounts(DefaultConstants.ROBOT_ENERGY_SHOOT))
	 * 		|	then result == false
	 */
	public boolean canShoot() {
		return !this.isTerminated() && this.getBoard() != null && PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - DefaultConstants.ROBOT_ENERGY_SHOOT.getAmount())
				&& this.canHaveAsEnergyLevel(this.getEnergyLevel().subtract(DefaultConstants.ROBOT_ENERGY_SHOOT));
	}
	
	/**
	 * When this is hit by a laser, he looses some of this energy limit.
	 * 
	 * @effect If this can not have the energyLimit, subtracted by some amount, this will have zero energy and will be terminated.
	 * 		| if !PhysicalAmount.isValidAmount(this.getEnergyLimit().getAmount() - DefaultConstants.ROBOT_BEEN_HIT.getAmount())
	 * 		|		|| !this.canHaveAsEnergyLimit(this.getEnergyLimit().subtractPhysicalAmounts(DefaultConstants.ROBOT_BEEN_HIT))
	 * 		|	then this.setEnergyLevel(PhysicalAmount.ZERO)
	 * 		|		 this.terminate()
	 * @post If this can have the energyLimit, subtracted by some amount, this will have that energyLimit.
	 * 		| if !PhysicalAmount.isValidAmount(this.getEnergyLimit().getAmount() - DefaultConstants.ROBOT_BEEN_HIT.getAmount())
	 * 		|		|| !this.canHaveAsEnergyLimit(this.getEnergyLimit().subtractPhysicalAmounts(DefaultConstants.ROBOT_BEEN_HIT))
	 * 		|	then (new this).getEnergyLimit().equals(this.canHaveAsEnergyLimit(this.getEnergyLimit().subtractPhysicalAmounts(DefaultConstants.ROBOT_BEEN_SHOT)))
	 * @post If this can have the energyLimit, subtracted by some amount, this will have his energyLevel if valid. Otherwise
	 * 		this will have the energyLimit as his energyLevel.
	 * 		| if !PhysicalAmount.isValidAmount(this.getEnergyLimit().getAmount() - DefaultConstants.ROBOT_BEEN_HIT.getAmount())
	 * 		|		|| !this.canHaveAsEnergyLimit(this.getEnergyLimit().subtractPhysicalAmounts(DefaultConstants.ROBOT_BEEN_HIT))
	 * 		|	if (new this).canHaveAsEnergyLevel(this.getEnergyLevel())
	 * 		|		then (new this).getEnergyLevel().equals((old this).getEnergyLevel())
	 * 		|	else
	 * 		|		(new this).getEnergyLevel().equals((new this).getEnergyLimit())
	 */
	@Override
	public void beenShot() {
		PhysicalAmount energyLevel = this.getEnergyLevel();
		this.setEnergyLevel(PhysicalAmount.ENERGY_ZERO);
		try{
			PhysicalAmount energyLimit = this.getEnergyLimit().subtract(DefaultConstants.ROBOT_BEEN_HIT);
			if(this.canHaveAsEnergyLimit(energyLimit)) {
				this.setEnergyLimit(energyLimit);
				if(this.canHaveAsEnergyLevel(energyLevel))
					this.setEnergyLevel(energyLevel);
				else
					this.setEnergyLevel(energyLimit);
			}	
			else
				this.terminate();
		}
		catch(NegativeAmountException e1){
			this.terminate();
		}
		
	}

	
//using-picking up-dropping items -------------------------------------------------------------------------------------------------------------
	
	/**
	 * Returns the number of items this robot is carrying.
	 */
	@Basic
	public int getNbUsableItems() {
		return usables.size();
	}
	
	/**
	 * Returns the element for which index items weight less.
	 * @throws IndexOutOfBoundsException
	 * 		When the index is not valid
	 * 		| index < 0 || index >= this.NbUsableItems()
	 */
	@Basic
	public Usable getUsableItemAt(int index) throws IndexOutOfBoundsException {
		return usables.get(index);
	}
	
	/**
	 * Returns all Usable items this robot is carrying.
	 * 
	 * @return All Usable items this robot is carrying.
	 * 		| for each i in {x|x>=0 && x<getNbUsableItems}
	 * 		|	result.get(i) == getUsableItemAt(i)
	 */
	public List<Usable> getAllUsables(){
		return new ArrayList<Usable>(usables);
	}
	
	/**
	 * Returns a set containing only usable items of the given class or usable items that extends the 
	 * given class.
	 * 
	 * @param E The class of which usable items must be returned of this robot.
	 * @return Each item that this robot contains and is not terminated, is returned.
	 * 		| for each usable in {getAllUsables()}
	 * 		|	if E.isInstance(usable)
	 * 		|		then result.contains(usable)
	 */
	public <E> Set<E> getAllItemsType(Class<E> E) {
		Set<E> itemsTypeE = new HashSet<E>();
		for(Usable lusUsable : usables)
			if(E.isInstance(lusUsable)) 
				itemsTypeE.add(E.cast(lusUsable));
		return itemsTypeE;
	}
	
	/**
	 * Checks whether this robot is carrying the usable.
	 * 
	 * @param usable The usable that the robot is or isn't carrying.
	 * @return true if and only if usable is in the list of items the robot is carrying.
	 * 		| result == getAllBatteries().contains(battery)
	 */
	public boolean possessesItem(Usable usable){
		return usables.contains(usable);
	}
	
	/**
	 * Checks whether all the Usable items the robot is currently carrying are valid.
	 * 
	 * @return true if and only if all the Usable items the robot is currently carrying are valid.
	 * 		| if for each usable in {this.getAllUsables()}
	 * 		|	this.canHaveAsUsableItem(usable) )
	 * 		| then result == true
	 * 		| else
	 * 		|	result == false
	 */
	public boolean hasProperUsableItems() {
		for(Usable usable : usables){
			if( !canHaveAsUsableItem(usable))
				return false;
		}
		return true;
	}
	
	/**
	 * Checks whether usable is a valid item for the robot to carry.
	 * 
	 * @param usable The usable to be checked.
	 * @return true if and only if the usable is not null, the usable isn't terminated and the usable is not placed on a board.
	 * 		| result == !( usable == null || usable.getBoard() != null )
	 */
	public boolean canHaveAsUsableItem(Usable usable) {
		if ( usable == null || usable.getBoard() != null )
			return false;
		return true;
	}

	/**
	 * Add usable to the collection of items the robot is carrying if the robot can carry this item.
	 * 
	 * @param usable The item to be added.
	 * @post The collection of items this robot is carrying will contain this usable, if the robot can carry this usable.
	 * 		| if canHaveAsUsableItem(usable)
	 * 		| 	then (new this).possessesItem(usable) == true
	 */
	public void addAsUsableItem(Usable usable) { // total
		if(canHaveAsUsableItem(usable))
			usables.add(usable);
	}
	
	/**
	 * Removes the item from the collection of items the robot is carrying, if the robot is carrying it.
	 * 
	 * @param usable The usable to be removed.
	 * @post The robot won't be carrying this usable.
	 * 		| !(new this).possessesItem(usable)
	 */
	public void removeAsUsableItem(Usable usable) { // total
		usables.remove(usable);
	}
	
	/**
	 * Returns the total weight this robot is carrying. Only not terminated items are taking into
	 * account.
	 * 
	 * @return The total weight the robot is carrying of not terminated items.
	 * 		| let weight be PhysicalAmount.WEIGHT_ZERO
	 * 		| for each usable in {this.getAllUsables()}
	 * 		|	if !usable.isTerminated()	
	 * 		|		then weight = weight.add(usable.getWeight());
	 * 		| result == weight
	 */
	public PhysicalAmount getWeightCarried() {
		PhysicalAmount weight = PhysicalAmount.WEIGHT_ZERO;
		for(Usable usable : this.getAllUsables())
			if(!usable.isTerminated())  
				weight = weight.add(usable.getWeight());
		return weight;
	}
	
	/**
	 * Controls if the robot can use this usable.
	 * 
	 * @param usable The usable to control.
	 * @return True if this is not terminated and usable is not null and this possesses the usable
	 * 		| result == !this.isTerminated() && usable != null && possessesItem(usable)
	 */
	public boolean canUse(Usable usable) {
		return !this.isTerminated() && usable != null && possessesItem(usable);
	}
	
	/**
	 * Uses the battery.
	 * 
	 * @param usable The usable to be used.
	 * @effect If this can use the usable, this will use the usable. If the usable is terminated, the usable will be drop.	
	 * 		| if canUse(usable)
	 * 		|	then if usable.isTerminated()
	 * 		|			then this.drop(usable)
	 * 		| 		 else
	 * 		| 			usable.use(this)
	 */ 
	public void use(Usable usable){ 	//Total
		if(canUse(usable)) {
			if(usable.isTerminated())
				drop(usable);
			else 
				usable.isUsed(this);			
		}
	}
	
	/**
	 * Checks whether the robot can pick up the usable.
	 * 
	 * @param usable The usable to be checked.
	 * @return true if and only if the usable is not null and the usable is placed on the same board (not null) and the same position as this robot
	 * 			and the robot is not terminated.
	 * 		| result == !this.isTerminated() && !this.possessesItem(usable) && this.getBoard() != null && usable != null &&
	 *		|	usable.getBoard() == this.getBoard() && usable.getPosition().equals(this.getPosition())
	 */
	public boolean canPickUp(Usable usable) {
		return !this.isTerminated() && !this.possessesItem(usable) && this.getBoard() != null && usable != null &&
				usable.getBoard() == this.getBoard() && usable.getPosition().equals(this.getPosition());
	}
	
	/**
	 * Let this robot pick up the usable.
	 * 
	 * @param usable The usable to be picked up.
	 * @effect Picks up the usable if possible
	 * 		| if canPickUp(usable)
	 * 		|	then battery.isPickedUp(this)
	 * @effect Add this usable to the collection of usables the robot is carrying.
	 * 		| if canPickUp(usable)	
	 * 		|	then this.addAsUsableItem(battery)
	 */
	public void pickUp(Usable usable){ 		//Total
		if(canPickUp(usable)) {
			usable.isPickedUp(this);
			addAsUsableItem(usable);
		}
	}
	
	/**
	 * Controls if the robot can drop this usable.
	 * 
	 * @param usable The usable to be controlled.
	 * @return True if this is not terminated and the usable is not null and this possesses the usable.
	 * 		| result == !this.isTerminated() && usable != null && this.possessesItem(usable)
	 */
	public boolean canDrop(Usable usable) {
		return !this.isTerminated() && usable != null && this.possessesItem(usable);
	}
	
	/**
	 * Drops the usable.
	 * 
	 * @param usable The usable to be dropped.
	 * @effect Sets the board of battery to null if the battery is terminated if possible.
	 * 		| if battery.isTerminated() && canDrop(usable)
	 * 		|	then battery.setBoard(null)
	 * @effect Drops the battery if possible.
	 * 		| if !battery.isTerminated() && canDrop(usable)
	 * 		| 	then battery.isDropped(this)
	 * @effect Removes the battery from the list of batteries this robot is carrying if possible.
	 * 		| if canDrop(usable)
	 * 		|	then this.removeAsUsableItem(battery)
	 */
	public void drop(Usable usable){
		if(canDrop(usable)) {
			if(usable.isTerminated()){
				usable.setBoard(null);
				usable.setPosition(this.getPosition());
			}
			else
				usable.isDropped(this);
			this.removeAsUsableItem(usable); // the Raw from battery.drop is resolved.
		}
	}
	
	/**
	 * Transfers all items of this robot to the given robot.
	 * 
	 * @param robot The robot to which the items should be transfered.
	 * @effect If the given robot is not null, isn't terminated, and if this robot isn't terminated, has an effective board and 
	 * 				if the boards of the two robots is the same and if they are standing next to each other
	 * 				then all items this robot is carrying are added to the given robot.
	 * 		| if robot != null && !robot.isTerminated() && !this.isTerminated() && this.getBoard() != null 
	 * 		|		&& this.getBoard()==robot.getBoard() && this.getPosition().nextTo(robot.getPosition())
	 * 		| 	then for each item in {this.getAllUsables()}
	 * 		|		robot.addAsUsableItem(item)
	 * @effect If the given robot is not null, isn't terminated, and if this robot isn't terminated, has an effective board and 
	 * 				if the boards of the two robots is the same and if they are standing next to each other
	 * 				then all items this robot is carrying are removed from robot.
	 * 		| if robot != null && !robot.isTerminated() && !this.isTerminated() && this.getBoard() != null 
	 * 		|		&& this.getBoard()==robot.getBoard() && this.getPosition().nextTo(robot.getPosition())
	 * 		| 	then for each item in {this.getAllUsables()}
	 * 		|		this.removeAsUsableItem(item)
	 */
	public void transferTo(Robot robot){ // total
		if( robot != null && !robot.isTerminated() && !this.isTerminated() && this.getBoard() != null 
				&& this.getBoard()==robot.getBoard() && this.getPosition().nextTo(robot.getPosition()) ){
			for(Usable item : this.getAllUsables()){
				robot.addAsUsableItem(item);
				this.removeAsUsableItem(item);
			}
		}
	}
	
	
	/**
	 * The list of objects the robot is currently carrying.
	 */
	private final SortedCollection<Usable> usables = new SortedCollection<Usable>();
	
//Moving defensive -----------------------------------------------------------------------------------------------------
	
	/**
	 * Moves the robot one time in the direction of its orientation if possible. 
	 * 
	 * @pre The robot must have enough energy to move.
	 * 		| let cost = DefaultConstants.ROBOT_ENERGY_MOVEMENT.add( DefaultConstants.ROBOT_ENERGY_MOVEMENT_PER_WEIGHT.multiply(this.getWeightCarried().getAmount()) )
	 * 		| PhysicalAmount.isValidAmount( (old this).getEnergyLevel().getAmount() - cost.getAmount() ) 
	 * 		| && canHaveAsEnergyLevel( (old this).getEnergyLevel().subtract(cost) )
	 * @effect If the robot isn't terminated, the robot will consume energy while moving.
	 * 		| if !isTerminated()
	 * 		|	then consumeEnergy( DefaultConstants.ROBOT_ENERGY_MOVEMENT.add( this.getWeightCarried().multiply(DefaultConstants.ROBOT_ENERGY_MOVEMENT_PER_WEIGHT)) )
	 * @effect If there is enough energy for a movement, then by moving the robot will get a new position, depending on its orientation.
	 * 		| if !isTerminated()
	 * 		| 	then this.setPosition( this.getPosition().move(this.getOrientation()) )
	 * @throws IllegalStateException
	 * 		The robot is terminated and can't be moved.
	 * 		| isTerminated()
	 * @throws IllegalPositionException
	 * 		If the robot will get a new position that doens't satisfy the class invariants of Position
	 * 		| !this.getPosition().isValidX((new this).getPosition().getX()) || !this.getPosition().isValidY((new this).getPosition().getY())
	 * @throws IllegalPositionOnBoardException
	 * 		If the robot will have a new position that can't contain this item according to canHaveAsPosition.
	 * 		| !canHaveAsPosition( (new this).getPosition() )
	 */
	public void move() throws IllegalStateException, IllegalPositionException, IllegalPositionOnBoardException {
		if(!isTerminated()) {
			this.setPosition(this.getPosition().move(this.getOrientation()));
			consumeEnergy(PhysicalAmountFactory.get().create(this.getWeightCarried().getAmount() * DefaultConstants.ROBOT_ENERGY_MOVEMENT_PER_WEIGHT, Unit.WATTSECOND).add(
					DefaultConstants.ROBOT_ENERGY_MOVEMENT));	
		}
		else
			throw new IllegalStateException("The robot is terminated");
	}
	
	/**
	 * Moves this robot and the other as close as possible to each other (they will end up with minimal Manhattan distance) given their energy level.
	 * 
	 * @param robot The robot next to which this robot must end, if possible.
	 * @post For every possible position of the robots on the board, if they can reach a combination of positions and are
	 * 		next to each other, then the total needed energy for both is greater or equal than the energy required to move to their new positions. 
	 * 		Otherwise, when they can reach the combination of positions but are not next to each other, then the Manhattan distance between them is greater or equal
	 * 		to the Manhattan distance after the movements executed by this method and the energy needed to get to this positions is smaller or equal 
	 * 		to any other combination that has the same ManhattenDistance.
	 * 		| this.getBoard().removeAsItem(this) 
	 * 		| robot.getBoard().removeAsItem(robot)
	 * 		| for each positionThis in {x | Position.class.isInstance(x) && this.getBoard().canHaveAsItem(new Robot(x))}
	 * 		|	 for each positionRobot in {x | Position.class.isInstance(x) && this.getBoard().canHaveAsItem(new Robot(x))}
	 * 		|		 for each orientationThis in {Orientation.values()}
	 * 		|		 	for each orientationRobot in {Orientation.values()}	
	 * 		|				if !( (this old).getEnergyRequiredToReach(positionThis) < 0 || (robot old).getEnergyRequiredToReach(positionRobot) < 0 )
	 * 		|			   		then if positionThis.nextTo(positionRobot)
	 * 		|							then (this old).getEnergyRequiredToReach((this new).getPosition()) + (robot old).getEnergyRequiredToReach((robot new).getPosition()) )
	 * 		|						 		 <= ( (this old).getEnergyRequiredToReach(positionThis) + (robot old).getEnergyRequiredToReach(positionRobot) )
	 * 		|						else
	 * 		|				 	    	then (new this).getPosition().getManhattanDistance((new robot).getPosition()) < positionThis.getManhattanDistace(positionOther)
	 * 		|									|| ( ((this old).getEnergyRequiredToReach((this new).getPosition()) + (robot old).getEnergyRequiredToReach((robot new).getPosition()))
	 * 		|						 				 <= ((this old).getEnergyRequiredToReach(positionThis) + (robot old).getEnergyRequiredToReach(positionRobot)) )
	 * 		| (new this).getBoard() == (old this).getBoard()
	 * 		| (new robot).getBoard() == (old robot).getBoard()
	 * @throws IllegalArgumentException
	 * 		If robot is null or if robot isn't on the same board as this robot or this and the robot are the same object.
	 * 		| if robot == null || this.getBoard() == null || this.getBoard() != robot.getBoard() || this == robot
	 * @throws IllegalStateException
	 * 			When this or the robot is terminated.
	 * 		| if this.isTerminated() || robot.isTerminated()
	 */
	
	public void moveNextTo(Robot robot) { 
		if(robot==null || this.getBoard() == null || this.getBoard()!= robot.getBoard() || this == robot)
			throw new IllegalArgumentException("robot is null or/and the boards of the two robots are not the same or/and the boards are null or/and the robots are the same");
		if(this.isTerminated() || robot.isTerminated())
			throw new IllegalStateException("this robot or/and the other one is/are terminated");
		
		ReachAllPossiblePositions[] temp = executeDijkstras(robot);
		ReachAllPossiblePositions dijkstraThis = temp[0];
		ReachAllPossiblePositions dijkstraRobot = temp[1];
		
		List<Vertex[]> combinations = crossProductMinimalManhattanDistance(robot, dijkstraThis, dijkstraRobot);// contains all combinations with the same minimum ManhattanDistance
			
		Vertex[] bestCombination = getBestCombinationMinimalEnergy(combinations);
		
		setRobotsToBestCombination(robot, bestCombination);
			
	}
	
	/**
	 * Creates and executes the ReachAllPossiblePositions-objects for robot and this.
	 * 
	 * @param robot The robot next to which this robot must end, if possible.
	 * @return Returns an array with at 0 the (executed) Dijkstra of this, and at 1 the (executed) Dijkstra of robot.
	 * 		| result[0] = (new ReachAllPossiblePositions(this)).run()
	 * 		| result[1] = (new ReachAllPossiblePositions(robot)).run()
	 */
	private ReachAllPossiblePositions[] executeDijkstras(Robot robot){
		ReachAllPossiblePositions[] result = new ReachAllPossiblePositions[2];
		
		ReachAllPossiblePositions dijkstraThis = new ReachAllPossiblePositions(this);
		ReachAllPossiblePositions dijkstraRobot = new ReachAllPossiblePositions(robot);
		
		Thread threadThis = new Thread(dijkstraThis);
		Thread threadRobot = new Thread(dijkstraRobot);
		
		threadThis.start();
		threadRobot.start();
		try {
			threadThis.join();
			threadRobot.join();
		} catch (InterruptedException e) {
			//If some concurrency exception occurs, the method will try to calculate the result sequential.
			if(dijkstraThis.getState() == DijkstraState.NOT_EXECUTED) {
				dijkstraThis = new ReachAllPossiblePositions(this);
				dijkstraThis.run();
			}
			if(dijkstraRobot.getState() == DijkstraState.NOT_EXECUTED) {
				dijkstraRobot = new ReachAllPossiblePositions(robot);
				dijkstraRobot.run();
			}
		}
		result[0] = dijkstraThis;
		result[1] = dijkstraRobot;
		return result;
	}

	
	/**
	 * Both ReachAllPossiblePositions objects will contain for both robots the minimal energy to reach all the reachable positions of the robots. This method takes
	 * the Cartesian product of all the combinations and the result contains only the combinations with minimal Manhattan distance.
	 * 
	 * @param robot The robot to move to.
	 * @param dijkstraThis The ReachAllPossiblePositions object of this, in valid state.
	 * @param dijkstraRobot The ReachAllPossiblePositions object of robot, in valid state.
	 * @pre The dijkstraThis object must be properly executed.
	 * 		| dijkstraThis.getState() == DijkstraState.EXECUTED_REACH_ALL_POSITIONS
	 * @pre The dijkstraRobot object must be properly executed.
	 * 		| dijkstraRobot.getState() == DijkstraState.EXECUTED_REACH_ALL_POSITIONS
	 * @pre The dijkstraThis object must have this as robot.
	 * 		| dijkstraThis.getRobot() == this
	 * @pre The dijkstraRobot object must have robot as robot.
	 * 		| dijkstraRobot.getRobot() == robot
	 * @return A list containing arrays for combinations of positions, reachable and with minimal Manhattan distance.
	 */
	private List<Vertex[]> crossProductMinimalManhattanDistance(Robot robot, ReachAllPossiblePositions dijkstraThis, ReachAllPossiblePositions dijkstraRobot) {
		//assert dijkstraThis.getState() == DijkstraState.EXECUTED_REACH_ALL_POSITIONS && dijkstraRobot.getState() == DijkstraState.EXECUTED_REACH_ALL_POSITIONS;
		assert dijkstraThis.getRobot() == this &&  dijkstraRobot.getRobot() == robot;
		
		List<Vertex[]> combinations = new ArrayList<Vertex[]>(); 
		Vertex[] temp = {new Vertex(this.getPosition(),this.getOrientation(),PhysicalAmountFactory.get().create(0,Unit.WATTSECOND)), 
				new Vertex(robot.getPosition(),robot.getOrientation(),PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND))};
		combinations.add(temp);
		
		for(Vertex vertexThis : dijkstraThis.getVisitedVertexes()){
			for(Vertex vertexRobot : dijkstraRobot.getVisitedVertexes()){
				Long currentMinimalManhattanDistance = (combinations.get(0)[0].getPosition().getManhattanDistance( combinations.get(0)[1].getPosition() )); // initialise the minimal manhattandistance to this of the firt combination
				Vertex temps[] = {vertexThis,vertexRobot};
				
				if (vertexThis.getPosition().getManhattanDistance(vertexRobot.getPosition())
						== currentMinimalManhattanDistance)
					combinations.add(temps);
				if (vertexThis.getPosition().getManhattanDistance(vertexRobot.getPosition())
						< currentMinimalManhattanDistance && vertexThis.getPosition().getManhattanDistance(vertexRobot.getPosition())!=0){
					combinations.clear();
					combinations.add(temps);
				}
			}		
		}
		return combinations;
	}
	
	/**
	 * Returns the combination with minimal energy in the combinations list. If there are several combinations with the same minimal energy, the last one in the list is returned.
	 * 
	 * @param combinations A list containing the possible combinations with the same minimal Manhattan distace.
	 * @pre The list cannot be empty.
	 * 		| !combinations.isEmpty()
	 * @return The combination with minimal energy to reach (the sum of the energies needed for the two robots). If there are several combinations with the same minimal energy, a random one is returned.
	 */
	private Vertex[] getBestCombinationMinimalEnergy(List<Vertex[]> combinations) {
		assert !combinations.isEmpty();
		PhysicalAmount neededEnergy = PhysicalAmountFactory.get().create(Double.POSITIVE_INFINITY,Unit.WATTSECOND);
		Vertex[] bestCombination = combinations.get(0);
		for(Vertex[] currentCombination : combinations){
			if( (currentCombination[0].getEnergyToReach().add(currentCombination[1].getEnergyToReach())).compareTo(neededEnergy)==-1 ){
				neededEnergy = currentCombination[0].getEnergyToReach().add(currentCombination[1].getEnergyToReach());
				bestCombination = currentCombination;
			}
		}
		return bestCombination;
	}
	
	/**
	 * Sets the robot and this to the given combination.
	 * 
	 * @param robot The robot to be set.
	 * @param bestCombination A array containing the position and orientation to be set for this and
	 * 							the robot.
	 * @pre The bestCombination[0] may not be null.
	 * 		| bestCombination[0] != null
	 * @pre This must have enough energy to reach the particular position.
	 * 		| PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - bestCombination[0].getEnergyToReach().getAmount())
	 * 		| && this.canHaveAsEnergyLevel(this.getEnergyLevel().subtract(bestCombination[0].getEnergyToReach())) 
	 * @pre This must can have the particular position.
	 * 		| this.canHaveAsPosition(bestCombination[0].getPosition())
	 * @pre The bestCombination[1] may not be null.
	 * 		| bestCombination[1] != null
	 * @pre robot must have enough energy to reach the particular position.
	 * 		| PhysicalAmount.isValidAmount(robot.getEnergyLevel().getAmount() - bestCombination[1].getEnergyToReach().getAmount())
	 * 		| && robot.canHaveAsEnergyLevel(robot.getEnergyLevel().subtractPhysicalAmounts(bestCombination[1].getEnergyToReach()))
	 * @pre This must can have the particular position.
	 * 		| robot.canHaveAsPosition(bestCombination[1].getPosition())
	 * @effect Sets this to the given bestCombination[0]
	 * 		| this.setRobotToBestCombination(bestCombination[0])
	 * @effect Sets robot to the given bestCombination[1]
	 * 		| robot.setRobotToBestCombination(bestCombination[1]) 
	 */
	private void setRobotsToBestCombination(Robot robot, Vertex[] bestCombination) {
		assert bestCombination[0] != null && bestCombination[1] != null;
		assert PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - bestCombination[0].getEnergyToReach().getAmount());
		assert PhysicalAmount.isValidAmount(robot.getEnergyLevel().getAmount() - bestCombination[1].getEnergyToReach().getAmount());
		assert this.canHaveAsEnergyLevel(this.getEnergyLevel().subtract(bestCombination[0].getEnergyToReach())) 
				&& robot.canHaveAsEnergyLevel(robot.getEnergyLevel().subtract(bestCombination[1].getEnergyToReach())) ;
		assert this.canHaveAsPosition(bestCombination[0].getPosition())
				&& robot.canHaveAsPosition(bestCombination[1].getPosition()) ;
		
		this.setRobotToBestCombination(bestCombination[0]);
		robot.setRobotToBestCombination(bestCombination[1]);
	}
	
	/**
	 * Sets this to the given bestCombination vertex.
	 * 
	 * @param bestCombination The bestCombination that will be set as position of this robot.
	 * @pre The bestCombination may not be null.
	 * 		| bestCombination != null
	 * @pre This must have enough energy to reach the particular position.
	 * 		| PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - bestCombination.getEnergyToReach().getAmount())
	 * 		| && this.canHaveAsEnergyLevel(this.getEnergyLevel().subtractPhysicalAmounts(bestCombination.getEnergyToReach()))
	 * @pre This must can have the particular position.
	 * 		| this.canHaveAsPosition(bestCombination.getPosition())
	 * @post The new position of this will the position of bestCombination.
	 * 		| (this new).getPosition() == bestCombination.getPosition()
	 * @effect This will consume an amount of energy given by bestCombination.
	 * 		| this.consumeEnergy(bestCombination.getEnergyToReach()
	 * @post The new orientation of this will be the orientation of bestCombination.
	 * 		| (this new).getOrientation() == bestCombination.getOrientation()
	 */
	private void setRobotToBestCombination(Vertex bestCombination){
		assert bestCombination != null;
		assert PhysicalAmount.isValidAmount(this.getEnergyLevel().getAmount() - bestCombination.getEnergyToReach().getAmount());
		assert this.canHaveAsEnergyLevel(this.getEnergyLevel().subtract(bestCombination.getEnergyToReach())) ;
		assert  this.canHaveAsPosition(bestCombination.getPosition());
		
		Board temp = this.getBoard();
		this.getBoard().removeAsItem(this);
		this.setPosition(bestCombination.getPosition());
		this.consumeEnergy(bestCombination.getEnergyToReach());
		this.setOrientation(bestCombination.getOrientation());
		temp.addAsItem(this);
	}

	
//Overriding from object -----------------------------------------------------------------------------
	
	/**
	 * Returns a textual specification of this robot.
	 * 
	 * @return A textual specification of this robot.
	 * 		| result == super.toString() + ", [" + this.getOrientation().toString() + "], [Total items: " + this.getNbUsableItems() + "], [Total weight: " + this.getWeightCarried() + "]"
	 */
	@Override
	public String toString() {
		return super.toString() + ", [" + this.getOrientation().toString() + "], [Total items: " + this.getNbUsableItems() + "], [Total weight: " + this.getWeightCarried() + "]";
	}
	
//LegalStatus ------------------------------------------------------------------------------------------------

	/**
	 * Controls if the positionItem satisfies all his class invariants.
	 * 
	 * @return False if the board is improperly.
	 * 		| if !hasProperBoard()
	 * 		|	then result == false
	 * @return False if the position is not legal.
	 * 		| if !canHaveAsPosition(this.getPosition())
	 * 		|	then result == false
	 * @return False if the energyLevel is not valid.
	 * 		| if !canHaveAsEnergyLevel(this.getEnergyLevel()
	 * 		|	then result == false
	 * @return False if the energyLimit is not valid.
	 * 		| if !canHaveAsEnergyLimit(this.getEnergyLimit())
	 * 		|	then result == false
	 * @return False if the orientation is not valid.
	 * 		| if !Robot.isValidOrientation(getOrientation())
	 * 		|	then result == false
	 * @return False if the usable items the robot carries are not valid.
	 * 		| if !hasProperUsableItems()
	 * 		|	then result == false
	 */
	@Override
	public boolean legalStatus() {
		return  super.legalStatus() && Robot.isValidOrientation(getOrientation()) && this.hasProperUsableItems();
	}	
}
